#ifndef __DRIVER_PL011_H_
#define __DRIVER_PL011_H_
#include "typedef.h"

#define RO const volatile word
#define RW volatile word
#define WO volatile word
#define KEEP(n,ide) word zreserve##ide[n];

#define UART_ECR UART_RSR

typedef struct PL011
{
    /**
     * @brief data register
     * @note 7:0 data
     * @note 8  FE, framing error if 1
     * @note 9  PE, parity error if 1
     * @note 10 BE, break error if 1
     * @note 11 OE, overrun error if 1
     * @note overrun means received data when fifo is full
     * @note 0x0
     */
    RW UART_DR;
    /**
     * @brief receive status register
     * @note if write to this status, clear the error status
     * @note also UART_ECR: error clear register
     * @note 0  FE, framing error if 1
     * @note 1  PE, parity error if 1
     * @note 2 BE, break error if 1
     * @note 3 OE, overrun error if 1
     * @note 0x4
     */
    RW UART_RSR;
    KEEP(4,r08to14);
    /**
     * @brief flag register
     * @note 8 RI, ring indicator
     * @note 7 TXFE, Transmit fifo is empty
     * @note 6 RXFF, receive fifo is full
     * @note 5 TXFF, Transmit fifo is full
     * @note 4 RXFE, receive fifo is empty
     * @note 3 BUSY, uart is transmitting data
     * @note 2 DCD, data carrier detect
     * @note 1 DSR, data set is ready
     * @note 0 CTS, clear to send
     * @note 0x1c
     */
    RO  UART_FR;
    KEEP(1, s0x1c);
    /**
     * @brief IrDA low power counter register
     * @note used for special case
     * @note 0x20
     */
    RW  UART_ILPR;
    /**
     * @brief Integer baud rate register
     * @note 15:0 baud divisor integer
     * @note 0x24
     */
    RW  UART_IBRD;
    /**
     * @brief fractional baud rate register
     * @note  fractional baud rate divisor
     * @note 0x28
     */
    RW  UART_FBRD;
    /**
     * @brief line control register bit22~bit29
     * @note 7   SPS, stick parity select
     * @note 6:5 WLEN, word len
     * @note 4   FEN, fifo enable
     * @note 3   STP2, two stop bits select
     * @note 2   EPS, even parity select
     * @note 1   PEN, parity enable
     * @note 0   BRK, send break
     * @note 0x2c
     */
    RW  UART_LCRH;
    /**
     * @brief control register
     * @note reset=0x300
     * @note 15 CTSEn, CTS hardware flow control enabled
     * @note 14 RTSEn, RTS hardware flow control enabled
     * @note 13 OUT2
     * @note 12 OUT1
     * @note 11 DTS
     * @note 10 DTR
     * @note 9  RXE, receive enable
     * @note 8  TXE, transmit enable
     * @note 7  LBE, loopback enable
     * @note 6:3 reserved
     * @note 2 SIRLP, SIR low  power IrDa mode
     * @note 1 SIREN, SIR enable
     * @note 0 UARTEN, uart enable
     * @note 0x30
     */
    RW UART_CR;
    /**
     * @brief interrupt fifo level select register
     * @note 5:3 Receive interrupt when fifo is 1/8, 2/8, 4/8, 6/8 or 7/8 full
     * @note 2:0 Transmit interrupt when fifo is 1/8, 2/8, 4/8, 6/8 or 7/8 full
     * @note number order is 0,1,2,3
     */
    RW UART_IFLS;
    /**
     * @brief interrupt mask set/clear register
     * @note 10 OEIM, overrun error mask
     * @note 9  BEIM, break error mask
     * @note 8  PEIM, parity error mask
     * @note 7  FEIM, framing error mask
     * @note 6  RTIM, receive timout mask
     * @note 5  TXIM, transmit mask
     * @note 4  RXIM, receive mask
     * @note 3  DSRMIM
     * @note 2  DCDMIM
     * @note 1  CTSMIM
     * @note 0  RIMIM
     */
    RW UART_IMSC;
    /**
     * @brief raw interrupt status register
     * @note 10 OERIS, overrun error mask
     * @note 9  BERIS, break error mask
     * @note 8  PERIS, parity error mask
     * @note 7  FERIS, framing error mask
     * @note 6  RTRIS, receive timout mask
     * @note 5  TXRIS, transmit mask
     * @note 4  RXRIS, receive mask
     * @note 3  DSRRMIS
     * @note 2  DCDRMIS
     * @note 1  CTSRMIS
     * @note 0  RIRMIS
     */
    RO UART_IS;
    /**
     * @brief masked interrupt status register
     * @note 10 OEMIS, overrun error mask
     * @note 9  BEMIS, break error mask
     * @note 8  PEMIS, parity error mask
     * @note 7  FEMIS, framing error mask
     * @note 6  RTMIS, receive timout mask
     * @note 5  TXMIS, transmit mask
     * @note 4  RXMIS, receive mask
     * @note 3  DSRMMIS
     * @note 2  DCDMMIS
     * @note 1  CTSMMIS
     * @note 0  RIMMIS
     */
    RO UART_MIS;
    /**
     * @brief interrupt clear register
     * @note 10 OEIC, overrun error mask
     * @note 9  BEIC, break error mask
     * @note 8  PEIC, parity error mask
     * @note 7  FEIC, framing error mask
     * @note 6  RTIC, receive timout mask
     * @note 5  TXIC, transmit mask
     * @note 4  RXIC, receive mask
     * @note 3  DSRMIC
     * @note 2  DCDMIC
     * @note 1  CTSMIC
     * @note 0  RIMIC
     */
    WO UART_ICR;
    /**
     * @brief DMA control register
     * @note DMA on error
     * @note TXDMAE, Transmit DMA enable
     * @note RXDMAE, Receive DMA enable
     */
    RW UART_DMACR;
    KEEP(12,r7cto4c);
} *PL011;



static inline boolean is_rx_empty(PL011 base)
{
    return CAST_AS(boolean, base->UART_FR & (1 << 4));
}

static inline boolean is_tx_full(PL011 base)
{
    return CAST_AS(boolean, base->UART_FR & (1 << 5));
}

static inline void enable_rx_interrupt(PL011 base)
{
    base->UART_IMSC |= (1<<4);
}

/**
 * @brief send a char by pl011 uart
 * 
 * @param base the base address of this uart
 * @param c the char needs go out
 * @return int 
 */
int uart_putc(address base, char c);

char uart_getc(address base);

void ack_receive_int(address base);
void uart_init(address base);

#endif//__DRIVER_PL011_H_